package com.backend.modules.notification.service.impl;

import com.backend.common.enums.UserType;
import com.backend.common.exception.BusinessException;
import com.backend.common.utils.SecurityUtils;
import com.backend.modules.notification.convert.NotificationConvert;
import com.backend.modules.notification.dto.NotificationQueryDTO;
import com.backend.modules.notification.entity.Notification;
import com.backend.modules.notification.repository.NotificationRepository;
import com.backend.modules.notification.service.NotificationQueryService;
import com.backend.modules.notification.vo.NotificationVO;
import com.backend.modules.system.entity.SysUser;
import com.backend.modules.system.service.SysUserService;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class NotificationQueryServiceImpl implements NotificationQueryService {

  private final NotificationRepository notificationRepository;
  private final SysUserService sysUserService;

  @Override
  public Page<NotificationVO> page(NotificationQueryDTO query, Pageable pageable) {
    // 获取当前登录用户

    SysUser currentUser = sysUserService.getCurrentUser();
    boolean isAdmin = Objects.equals(currentUser.getUserType(), UserType.ADMIN.getValue());
    Specification<Notification> spec = (root, criteriaQuery, cb) -> {
      List<Predicate> predicates = new ArrayList<>();

      if (!isAdmin) {
        // 只查询当前用户的通知
        predicates.add(cb.equal(root.get("receiverId"), SecurityUtils.getCurrentUserId()));
      }

      // 通知类型
      if (StringUtils.hasText(query.getType())) {
        predicates.add(cb.equal(root.get("type"), query.getType()));
      }

      // 是否已读
      if (query.getRead() != null) {
        predicates.add(cb.equal(root.get("read"), query.getRead()));
      }

      // 时间范围
      if (query.getStartTime() != null) {
        predicates.add(cb.greaterThanOrEqualTo(
            root.get("createTime"), query.getStartTime()));
      }
      if (query.getEndTime() != null) {
        predicates.add(cb.lessThanOrEqualTo(
            root.get("createTime"), query.getEndTime()));
      }

      return cb.and(predicates.toArray(new Predicate[0]));
    };

    return notificationRepository.findAll(spec, pageable)
        .map(NotificationConvert::convert);
  }

  @Override
  public long countUnread() {
    return notificationRepository.countByReceiverIdAndReadFalse(
        SecurityUtils.getCurrentUserId());
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void markAsRead(Long id) {
    Notification notification = notificationRepository.findById(id)
        .orElseThrow(() -> new BusinessException("通知不存在"));
    SysUser currentUser = sysUserService.getCurrentUser();
    boolean isAdmin = Objects.equals(currentUser.getUserType(), UserType.ADMIN.getValue());
    // 验证是否是当前用户的通知
    if (!isAdmin && !notification.getReceiverId().equals(SecurityUtils.getCurrentUserId())) {
      throw new BusinessException("无权操作此通知");
    }

    if (isAdmin) {
      // 新增一个管理员删除通知
    }
    notification.setRead(true);
    notificationRepository.save(notification);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void markAsRead(List<Long> ids) {
    List<Notification> notifications = notificationRepository.findAllById(ids);

    // 验证是否都是当前用户的通知
    Long currentUserId = SecurityUtils.getCurrentUserId();
    if (notifications.stream()
        .anyMatch(n -> !n.getReceiverId().equals(currentUserId))) {
      throw new BusinessException("无权操作部分通知");
    }

    notifications.forEach(n -> n.setRead(true));
    notificationRepository.saveAll(notifications);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void markAllAsRead() {
    // 查询当前用户的所有未读通知
    Specification<Notification> spec = (root, criteriaQuery, cb) -> {
      List<Predicate> predicates = new ArrayList<>();
      predicates.add(cb.equal(root.get("receiverId"), SecurityUtils.getCurrentUserId()));
      predicates.add(cb.equal(root.get("read"), false));
      return cb.and(predicates.toArray(new Predicate[0]));
    };

    List<Notification> notifications = notificationRepository.findAll(spec);
    notifications.forEach(n -> n.setRead(true));
    notificationRepository.saveAll(notifications);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void delete(Long id) {
    // 验证通知是否存在且属于当前用户
    Notification notification = notificationRepository.findById(id)
        .orElseThrow(() -> new BusinessException("通知不存在"));

    if (!notification.getReceiverId().equals(SecurityUtils.getCurrentUserId())) {
      throw new BusinessException("无权删除该通知");
    }

    notificationRepository.deleteById(id);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void delete(List<Long> ids) {
    // 验证通知是否都属于当前用户
    List<Notification> notifications = notificationRepository.findAllById(ids);

    for (Notification notification : notifications) {
      if (!notification.getReceiverId().equals(SecurityUtils.getCurrentUserId())) {
        throw new BusinessException("无权删除部分通知");
      }
    }

    notificationRepository.deleteAllById(ids);
  }
}